package ps.client.net;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;

import ps.net.Packet;



public class ServerInfo extends Thread {
    
    Socket socket;
    SocketAddress socketAddress;
    
    ByteArrayOutputStream buffer = new ByteArrayOutputStream(16 * 1024);
    
    ClientPacketHandler clientPacketHandler;
    
    InputStream in;
    OutputStream out;
    
    boolean running = true;
    boolean connected = false;
    
    long lastRecievedMsgTime = 0;
    
    public ServerInfo(ClientPacketHandler clientPacketHandler) {
        super("ServerInfo");
        this.clientPacketHandler = clientPacketHandler;
        
        start();
    }
    
    public void connect(SocketAddress socketAddress, int timeout) throws IOException {
        this.socketAddress = socketAddress;
        
        disconnect();
        
        socket = new Socket();
        socket.setTcpNoDelay(true);
        socket.setPerformancePreferences(0, 1, 0);
//        socket.setPerformancePreferences(0, 0, 1);
        socket.connect(socketAddress, timeout);
        
        System.out.println("new socket connected (" + socket.getReceiveBufferSize() + ")");
        
        in = socket.getInputStream();
        out = socket.getOutputStream();
        
        connected = true;
    }
    
    public void reconnect(int timeout) throws IOException {
        connect(socketAddress, timeout);
    }
    
    public void disconnect() {
        connected = false;
        
        try {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
            if (socket != null) {
                System.out.println("SERVER SOCKET CLOSED");
                socket.close();
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        
        socket = null;
    }
    
    public void close() {
        running = false;
        disconnect();
    }
    
    public synchronized void send(Packet packet) {
        if (connected) {
            try {
//                System.out.println("SEND: " + packet);
                
                buffer.reset();
                packet.writePacket(buffer);
                buffer.writeTo(out);
                out.flush();
            
            } catch (SocketException ex) {
                if (running && connected) {
                    disconnect();
                    fireConnectionLost();
                }
            } catch (IOException ex) {
                if (running && connected) {
                    ex.printStackTrace();
                    disconnect();
                    fireConnectionLost();
                }
            }
        }
    }
    
    @Override
    public void run() {
        while (running) {
            try {
                if (connected) {
                    Packet packet = new Packet();
                    packet.readPacket(in);
                    
                    if (packet.getType() >= 0) {
//                        System.out.println("RECIEVED: " + packet);
                        
                        setLastRecievedMsgTime(System.currentTimeMillis());
                        clientPacketHandler.addRecievedPacket(packet);
                        
                        if (packet.isTypeOf(Packet.TYPE_LOGOUT)) {
                            connected = false;
                        }
                        
                        Thread.yield();
                    } else {
                        disconnect();
                        fireConnectionLost();
                    }
                } else {
                    sleep(100);
                }
            } catch (SocketException ex) {
                if (running && connected) {
                    disconnect();
                    fireConnectionLost();
                }
            } catch (Exception ex) {
                if (running && connected) {
                    ex.printStackTrace();
                    disconnect();
                    fireConnectionLost();
                }
            }
        }
    }
    
    public long getLastRecievedMsgTime() {
        return lastRecievedMsgTime;
    }
    
    public void setLastRecievedMsgTime(long lastRecievedMsgTime) {
        this.lastRecievedMsgTime = lastRecievedMsgTime;
    }
    
    protected void fireConnectionLost() {
    }
    
}
